package com.yonyou.ypd.bill.service.impl;

import com.yonyou.ucf.mdd.api.interfaces.rpc.IRefApi;
import com.yonyou.ucf.mdd.common.model.ref.RefEntity;
import com.yonyou.ucf.mdd.common.model.uimeta.filter.vo.FilterVO;
import com.yonyou.ucf.mdd.ext.bill.dto.BillDataDto;
import com.yonyou.ucf.mdd.ext.dubbo.DubboReferenceUtils;
import com.yonyou.ucf.mdd.ext.model.BillContext;
import com.yonyou.ucf.mdd.ext.ref.service.IRefService;
import com.yonyou.ucf.mdd.ext.util.BillContextUtils;
import com.yonyou.ypd.bill.basic.BillActionInfo;
import com.yonyou.ypd.bill.basic.BillReferInfo;
import com.yonyou.ypd.bill.basic.constant.BillActionEnum;
import com.yonyou.ypd.bill.basic.constant.BillCommonConstant;
import com.yonyou.ypd.bill.basic.constant.RefTypeEnum;
import com.yonyou.ypd.bill.basic.entity.BillDOUtils;
import com.yonyou.ypd.bill.context.BillQueryContext;
import com.yonyou.ypd.bill.context.RefQueryParam;
import com.yonyou.ypd.bill.extension.YpdExtensionExecutor;
import com.yonyou.ypd.bill.infrastructure.service.api.IBillRefService;
import com.yonyou.ypd.bill.infrastructure.service.api.IYpdExtRefService;
import com.yonyou.ypd.bill.plugin.BillPluginExcutor;
import com.yonyou.ypd.bill.plugin.itf.IBillQueryActionPlugin;
import com.yonyou.ypd.dispatcher.BeanRegister;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 单据参照查询服务
 * @author ypd
 * @date 2021/6/5 8:30 AM
 */
@Slf4j
@Component
public class BillRefServiceImpl implements IBillRefService {

    @Autowired
    private BillPluginExcutor billPluginExcutor;
    @Autowired
    protected YpdExtensionExecutor extensionExecutor;
    @Autowired
    private BeanRegister<String, BillReferInfo> beanRegister;
    @Autowired
    private IRefService refService;

    private final String PARAM_SERVICECODE = "serviceCode";

    @Override
    public RefEntity queryRefMetaEntity(String domain, String refCode) throws Exception {
        RefEntity refEntity = refService.getRefEntityByCode(refCode, domain);
        return refEntity;
    }

    @Override
    public Object queryRemoteRefData(BillQueryContext billQueryContext) throws Exception {
        //参照元数据
        RefEntity refEntity = billQueryContext.getRefMetaInfo();
        //参照查询参数
        RefQueryParam refQueryParam = billQueryContext.getRefQueryParam();
        Map<String, Object> refParam = this.genRemoteRefParam(billQueryContext, refQueryParam);

        //构造参照查询的上下文信息
        String cBillNo = billQueryContext.getBaseBillContext().getcBillNo();
        BillContext billContext = this.genRemoteMddBillContext(billQueryContext, cBillNo);

        // 原厂参照参数refParam处理,refParam.put("externalData")和refParam.put("extendCondition") 可扩展
        this.processRemoteRefParams(billQueryContext, refEntity.getCode(), refParam);
        //远程参照
        IRefApi refAPI = DubboReferenceUtils.getDubboService(IRefApi.class, refEntity.outDomain, null);

        Object refData = refAPI.getRefData(billContext, refEntity, refParam);
        return refData;
    }

    protected void processRemoteRefParams(BillQueryContext billContext, String refCode, Map<String, Object> refParam) throws Exception {
        billPluginExcutor.commonDoPlugin(billContext, IBillQueryActionPlugin.class, null,
                iBillBasePlugin -> ((IBillQueryActionPlugin) iBillBasePlugin).processRemoteRefParams(billContext, refCode, refParam));
    }

    protected BillContext genRemoteMddBillContext(BillQueryContext billQueryContext, String billNo) {
        BillContext billContext = null;
        if(StringUtils.isEmpty(billNo)){
            billContext = new BillContext();
        }else{
            billContext = BillContextUtils.getBillContext(billNo);
            if (null == billContext) {
                billContext = new BillContext();
                billContext.setAction("refer");
                billContext.setBillnum(billNo);
            }
            BillDataDto billDataDTO = new BillDataDto();
            Map<String, Object> externalDataMap = getStringObjectMap(billQueryContext);//externalData不含有serviceCode的情况，手动塞入。处理ISV主组织参照查询权限不生效的问题
            billDataDTO.setExternalData(externalDataMap);
            billDataDTO.setQuerySchema(billQueryContext.getRefQueryParam().getQuerySchema());
            billDataDTO.setCondition(billQueryContext.getCondition());
            billContext.setParamObj(billDataDTO);
            if (null != billQueryContext.getRefQueryParam()) {
                billDataDTO.setIsMasterOrg(billQueryContext.getRefQueryParam().getIsMasterOrg());
            }
        }
        billContext.setAuthId(billQueryContext.getBaseBillContext().getServiceCode());// 赋值serviceCode --yanx于2022/5/19注释
//        billContext.setbRowAuthControl(billQueryContext.getBaseBillContext().isDataPowerEnable());// dataPowerEnable能够被插件修改，统一赋值 --yanx于2022/7/13注释
        billContext.setbRowAuthControl(false);// 主表受数据权限管控，子表不受数据权限管控的场景，赋值true会导致子表也受控制

        return billContext;
    }

    protected Map<String, Object> genRemoteRefParam(BillQueryContext billQueryContext, RefQueryParam refQueryParam) {
        Map<String, Object> refParam = refQueryParam.toMap();
        //转换data
        refParam.put("data", BillDOUtils.billDOsToMDDRefDataMap(refQueryParam.getData()));
        if (StringUtils.isNotBlank(billQueryContext.getBaseBillContext().getMasterOrgValue())) {
            refParam.put("masterOrgValue",billQueryContext.getBaseBillContext().getMasterOrgValue());
        }
        //补充其他参数
        refParam.put("tenantId", billQueryContext.getBaseBillContext().getInvocationInfo().getYhtTenantId());
        // 获取远程树参照数据不分页 --yanx于2022/3/11注释
        if("grid".equals(refQueryParam.getDataType())) {
            refParam.put("page", billQueryContext.getPage());
        } else if("tree".equals(refQueryParam.getDataType())){
            FilterVO condition = billQueryContext.getCondition();
            if(ArrayUtils.isNotEmpty(condition.getCommonVOs()) || ArrayUtils.isNotEmpty(condition.getSimpleVOs()) || condition.getQueryConditionGroup() != null){
                refParam.put("treeCondition",billQueryContext.getCondition());
            }
        }
        Map<String, Object> externalDataMap = getStringObjectMap(billQueryContext);//externalData不含有isvServiceCode的情况，手动塞入。处理ISV主组织参照查询权限不生效的问题

        refParam.put("externalData", externalDataMap);
        refParam.put("extendCondition", refQueryParam.getExtendCondition());// 远程参照支持extendCondition --yanx于2022/7/1注释
        if (null != refQueryParam.getQueryOrders()) {// 远程参照refParam支持queryOrders --yanx于2022/6/15注释
            refParam.put("queryOrders", refQueryParam.getQueryOrders());
        }

        //将调用方的扩展信息传到服务提供方
        refParam.put("actionInfo",billQueryContext.getBaseBillContext().getActionInfo());
        refParam.put("invocationInfo",billQueryContext.getBaseBillContext().getInvocationInfo());
        refParam.put("treeMetaFullName",billQueryContext.getBaseBillContext().getTreeMetaFullName());
        String refDataType = refQueryParam.getDataType();
        refParam.put("refDataType",refDataType);
        refParam.put("formFullName", billQueryContext.getBaseBillContext().getMetaFullName());
        refParam.put("custMap", billQueryContext.getBaseBillContext().getCustMap());//自定义扩展Map传递,mdd参照提供方可能需要这个参数
        refParam.put("condition",billQueryContext.getCondition());

        return refParam;
    }

    private Map<String, Object> getStringObjectMap(BillQueryContext billQueryContext) {
        Map<String, Object> externalDataMap = billQueryContext.getBaseBillContext().getActionInfo().getExternalData();
        if(ObjectUtils.isNotEmpty(billQueryContext.getBaseBillContext().getServiceCode())) {
            if(null == externalDataMap || externalDataMap.isEmpty()) {
                Map<String, Object> externalDataBac = new HashMap<>();
                externalDataBac.put(PARAM_SERVICECODE, billQueryContext.getBaseBillContext().getServiceCode());
                externalDataMap = externalDataBac;
            } else {
                if(externalDataMap.containsKey(PARAM_SERVICECODE)) {
                    return externalDataMap;
                }
                externalDataMap.put(PARAM_SERVICECODE, billQueryContext.getBaseBillContext().getServiceCode());
            }
        }
        return externalDataMap;
    }

    /**
     * @Description 路由匹配参照数据查询实现bean
     * @Author yanx
     * @Date 2023/5/26
     * @param
     */
    @Override
    public Object queryLocalRefData(BillQueryContext billContext) throws Exception {
        BillActionInfo origActionInfo = billContext.getBaseBillContext().getActionInfo();
        BillReferInfo referInfo = this.genReferInfo(origActionInfo);
        IYpdExtRefService extRefService = beanRegister.lookup(referInfo);

        RefEntity refEntity = billContext.getRefMetaInfo();
        RefQueryParam refQueryParam = billContext.getRefQueryParam();
        return extRefService.queryRefData(billContext, refEntity, refQueryParam);// 走action路由 --yanx于2023/5/18注释
    }

    private BillReferInfo genReferInfo(BillActionInfo origActionInfo) {
        BillReferInfo referInfo = new BillReferInfo(BillActionEnum.ACTIONCODE_REFDATA);
        referInfo.setBusiObj(origActionInfo.getBusiObj());
        referInfo.setRefCode(origActionInfo.getRefCode());
        referInfo.setBillNum(origActionInfo.getBillNum());

        return referInfo;
    }

    /**
     * 处理参照查询参数信息
     *
     */
    @Override
    public void processRefQueryInfo(RefQueryParam refQueryParam, BillQueryContext billContext) throws Exception {
        if (refQueryParam != null) {
            billContext.setRefQueryParam(refQueryParam);
            RefEntity refMetaInfo = this.queryRefMetaEntity(refQueryParam.getDomain(), refQueryParam.getRefCode());
            billContext.setRefMetaInfo(refMetaInfo);
            if (refMetaInfo != null) {
                // 不再使用refType查RefMetaEntity --yanx于2023/8/1注释
//                if (refMetaInfo.getRefType() != null && !(refMetaInfo.getRefType().equals(refQueryParam.getRefCode()))) {
//                    refMetaInfo = this.queryRefMetaEntity(refQueryParam.getDomain(), refMetaInfo.getRefType());
//                }
                String refFullname = StringUtils.isEmpty(refMetaInfo.getCDataGrid_FullName()) ? refMetaInfo.getCDataClass_FullName() : refMetaInfo.getCDataGrid_FullName();
                if(Objects.nonNull(refQueryParam.getDataType())){
                    switch (refQueryParam.getDataType()) {
                        case RefTypeEnum.REF_TYPE_GRID://表格
                            refFullname = refMetaInfo.getCDataGrid_FullName();
                            break;
                        case RefTypeEnum.REF_TYPE_TREE://树
                            refFullname = refMetaInfo.getCDataClass_FullName();
                    }
                }
                refQueryParam.setMetaFullName(refFullname);
                // TODO: 处理参照主组织和数据权限
//                billDataAuthService.handleAuthCondition(billContext, refQueryParam);
            }

        }

    }

}
